package academic.concordia.bankofquebec.managedbean;

import java.io.IOException;
import java.io.Serializable;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.regex.Pattern;

import javax.annotation.PostConstruct;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.component.UIComponent;
import javax.faces.component.UIInput;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;

import academic.concordia.bankofquebec.bean.authentication.IAuthenticationBean;
import academic.concordia.bankofquebec.bean.authentication.MyAuthenticationToken;
import academic.concordia.bankofquebec.bean.client.IClientBean;
import academic.concordia.bankofquebec.bean.session.SessionData;
import academic.concordia.bankofquebec.entity.Client;
import academic.concordia.bankofquebec.entity.IdentificationType;

@ManagedBean(name="clientManagedBean")
@Scope("session")
public class ClientManagedBean implements Serializable {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	private Client client;
	
	@Autowired
	IAuthenticationBean authenticationBean;
	
	@ManagedProperty(value="#{ClientBean}")
	IClientBean clientBean;
	
	@ManagedProperty(value="#{SessionData}")
	private SessionData sessionData;
	
	private Map<String, String> identificationTypes;
	
	@PostConstruct
    public void init() {
		System.out.println("clientBean in client managed bean: " + clientBean );
		populateIdentificationTypes();
        this.client = new Client();
    }
	
	/**
	 * Get the available identification types
	 * 
	 * @return
	 */
	public void populateIdentificationTypes() {
		identificationTypes = new LinkedHashMap<String, String>();
		for(IdentificationType identificationType : clientBean.getIdentificationTypes()) {
			identificationTypes.put(String.valueOf(identificationType.toString()), identificationType.toString());
		}
	}
	
	public String createClient() {
		
		try {
			String clientCreationResponse = clientBean.createClient(this.client);
			System.out.println("is client created: " + clientCreationResponse);
			if(clientCreationResponse.equals("SUCCESS")){
				return sessionData.getNavigation();
			}
			else {
				// invalid
				FacesContext facesContext = FacesContext.getCurrentInstance();
				FacesMessage facesMessage = new FacesMessage(clientCreationResponse);
				facesContext.addMessage(null, facesMessage);
	            return "";
			}
		} catch(DataIntegrityViolationException e) {
			// invalid
			FacesContext facesContext = FacesContext.getCurrentInstance();
			FacesMessage facesMessage = new FacesMessage("Error creating user " + client.getName() + ", the identificaction " + client.getIdNumber()
					+ " was already registred. ");
			facesContext.addMessage(null, facesMessage);
            return "";
		}
	} 

	public Client getClient() {
		return client;
	}

	public void setClient(Client client) {
		this.client = client;
	}
	
	public void checkClientId(FacesContext context, UIComponent toValidate, Object value) {
		boolean result = ClientManagedBean.validateAlphaNumericValues((String) value);
		if(!result) {
			((UIInput)toValidate).setValid(false);
			String message = "Client identification contains special characters";
		    context.addMessage(toValidate.getClientId(context),
		      new FacesMessage(message));
		}
	}
	
	public void checkClientPassword(FacesContext context, UIComponent toValidate, Object value) {
		boolean result = ClientManagedBean.validateAlphaNumericValues((String) value);
		if(!result) {
			((UIInput)toValidate).setValid(false);
			String message = "Client password contains special characters";
		    context.addMessage(toValidate.getClientId(context),
		      new FacesMessage(message));
		}
	}
	
	public void checkClientTelephone(FacesContext context, UIComponent toValidate, Object value) {
		boolean result = ClientManagedBean.validateNumericValues((String) value);
		if(!result) {
			((UIInput)toValidate).setValid(false);
			String message = "Client telephone must contains only numbers";
		    context.addMessage(toValidate.getClientId(context),
		      new FacesMessage(message));
		}
	}
	
	public void checkClientPasswordIntegrity(FacesContext context, UIComponent toValidate, Object value) {
		
		boolean result = ClientManagedBean.validateAlphaNumericValues((String) value);
		if(!result) {
			((UIInput)toValidate).setValid(false);
			String message = "Client password contains special characters";
		    context.addMessage(toValidate.getClientId(context),
		      new FacesMessage(message));
		} else {
			// TODO - Validate that contains number and upper case
		}
	}
	
	private static Pattern alphaNumericPattern = Pattern.compile("^[A-Za-z0-9]+$");
	private static Pattern numericPattern = Pattern.compile("^[0-9]+$");
	
    private static boolean validateAlphaNumericValues(String s) {
        return alphaNumericPattern.matcher(s).matches();
    }
    
    private static boolean validateNumericValues(String s) {
        return numericPattern.matcher(s).matches();
    }
	
	// This is the action method called when the user clicks the "login" button
    public String doLogin() throws IOException, ServletException
    {
        ExternalContext context = FacesContext.getCurrentInstance().getExternalContext();
        
        RequestDispatcher dispatcher = ((ServletRequest) context.getRequest())
                .getRequestDispatcher("/j_spring_security_check?j_username=" + client.getIdentificationType().toString() + "-" + client.getIdNumber()
                                + "&j_password=" + client.getPassword());
        
        dispatcher.forward((ServletRequest) context.getRequest(),
                (ServletResponse) context.getResponse());
 
        FacesContext.getCurrentInstance().responseComplete();
        // It's OK to return null here because Faces is just going to exit.
        return null;
    }

	public IClientBean getClientBean() {
		return clientBean;
	}

	public void setClientBean(IClientBean clientBean) {
		this.clientBean = clientBean;
	}

	public void setIdentificationTypes(Map<String, String> identificationTypes) {
		this.identificationTypes = identificationTypes;
	}
	
	public Map<String, String> getIdentificationTypes() {
		return identificationTypes;
	}

	public SessionData getSessionData() {
		return sessionData;
	}

	public void setSessionData(SessionData sessionData) {
		this.sessionData = sessionData;
	}
	
	
}


